home *** CD-ROM | disk | FTP | other *** search
- #undef PROCLOG
-
- /* Non pre-empting synchronization kernel, machine-independent portion */
- #if defined(PROCLOG) || defined(PROCTRACE)
- #include <stdio.h>
- #endif
- #include <dos.h>
- #include <setjmp.h>
- #include "global.h"
- #include "mbuf.h"
- #include "proc.h"
- #include "timer.h"
- #include "socket.h"
- #include "daemon.h"
- #include "hardware.h"
- #ifdef PROCLOG
- #include "files.h"
- #endif
-
- #ifdef PROCLOG
- FILE *proclog;
- #endif
-
- static int Stkchk = 1;
- struct proc *Curproc = NULLPROC; /* Currently running process */
- struct proc *Rdytab = NULLPROC; /* Processes ready to run (not including curproc) */
- struct proc *Waittab = NULLPROC; /* Waiting process list */
- struct proc *Susptab = NULLPROC; /* Suspended processes */
- static struct mbuf *Killq;
-
- /*----------------------------------------------------------------------*
- * primitive semaphore operation to serialize resource access (DK5DC) *
- * semawait waits for a semaphore to become free (0). *
- * If req is True, the semaphore will be incremented immediatly *
- * *
- * semrel will decrement the semaphore and set it to 0 if it becomes *
- * negative *
- *-----------------------------------------------------------------------*/
-
- void
- semwait(int *sema,int req)
- {
- while(*sema > 0)
- pwait(sema);
- if (req)
- *sema += 1; /* now lock it */
- }
-
- void
- semrel(int *sema)
- {
- if ((*sema -= 1) <= 0)
- *sema = 0;
- psignal(sema,0); /* signal to everbody who's waiting*/
-
- }
-
- /* Append proc entry to end of appropriate list */
- static void near
- addproc(struct proc *entry) /* Pointer to entry */
- {
- int i_state;
- struct proc **head;
-
- if(entry == NULLPROC) {
- return;
- }
- switch(entry->state){
- case READY:
- head = &Rdytab;
- break;
- case WAITING:
- head = &Waittab;
- break;
- case SUSPEND:
- case SUSPEND | WAITING:
- head = &Susptab;
- break;
- }
- i_state = dirps();
-
- entry->next = NULLPROC;
-
- if(*head == NULLPROC) {
- /* Empty list, stick at beginning */
- *head = entry;
- } else {
- struct proc *pp;
-
- /* Find last entry on list */
- for(pp = *head; pp->next != NULLPROC; pp = pp->next)
- ;
- pp->next = entry;
- }
- restore(i_state);
- }
-
- /* Remove a process entry from the appropriate table */
- static void near
- delproc(struct proc *entry) /* Pointer to entry */
- {
- int i_state;
- struct proc *pp = NULLPROC, *pplast = NULLPROC, **head;
-
- if(entry == NULLPROC) {
- return;
- }
- i_state = dirps();
-
- switch(entry->state) {
- case READY:
- head = &Rdytab;
- break;
- case WAITING:
- head = &Waittab;
- break;
- case SUSPEND:
- case SUSPEND|WAITING:
- head = &Susptab;
- break;
- }
-
- for(pp = *head; pp != NULLPROC; pplast = pp, pp = pp->next) {
- if(pp == entry) {
- if(pplast != NULLPROC) {
- pplast->next = pp->next;
- } else {
- *head = pp->next;
- }
- break;
- }
- }
- restore(i_state);
- }
-
- /* Create a process descriptor for the main function. Must be actually
- * called from the main function!
- * Note that standard I/O is NOT set up here.
- */
- struct proc *
- mainproc(char *name)
- {
- struct proc *pp;
- /* Create process descriptor */
- /* Don't call the xallocw functions! - DB3FL.920801 */
- pp = mxalloc(sizeof(struct proc));
-
- /* Create name */
- sprintf(pp->name,"%.16s",name);
-
- pp->stksize = 0;
-
- /* Make current */
- pp->state = READY;
- Curproc = pp;
-
- #ifdef PROCLOG
- proclog = fopen("\proclog",APPEND_TEXT);
- #endif
-
- return pp;
- }
-
- /* Create a new, ready process and return pointer to descriptor.
- * The general registers are not initialized, but optional args are pushed
- * on the stack so they can be seen by a C function.
- */
- struct proc *
- newproc(
- char *name, /* Arbitrary user-assigned name string */
- unsigned int stksize, /* Stack size in words to allocate */
- void (*pc)(), /* Initial execution address */
- int iarg, /* Integer argument (argc) */
- void *parg1, /* Generic pointer argument #1 (argv) */
- void *parg2, /* Generic pointer argument #2 (session ptr) */
- int freeargs) /* if set, free args list on termination */
- {
- struct proc *pp;
- int i;
-
- if(Stkchk) {
- chkstk();
- }
- /* Create process descriptor */
- pp = mxallocw(sizeof(struct proc));
-
- /* Allocate stack */
- pp->stack = cxallocw(sizeof(int16),stksize);
- pp->stksize = stksize;
-
- /* Create name */
- sprintf(pp->name,"%.16s",name);
-
- /* Initialize stack for high-water check */
- for(i = 0; i < pp->stksize; i++) {
- pp->stack[i] = STACKPAT;
- }
- /* Do machine-dependent initialization of stack */
- psetup(pp,iarg,parg1,parg2,pc);
-
- pp->freeargs = freeargs;
- pp->iarg = iarg;
- pp->parg1 = parg1;
- pp->parg2 = parg2;
-
- /* Inherit creator's input and output sockets */
- usesock(Curproc->input);
- pp->input = Curproc->input;
- usesock(Curproc->output);
- pp->output = Curproc->output;
-
- /* Add to ready process table */
- pp->state = READY;
- addproc(pp);
- return pp;
- }
-
- /* Free resources allocated to specified process. If a process wants to kill
- * itself, the reaper is called to do the dirty work. This avoids some
- * messy situations that would otherwise occur, like freeing your own stack.
- */
- void
- killproc(struct proc *pp)
- {
- char **argv;
- #ifdef PROCLOG
- extern int stkutil __ARGS((struct proc *pp));
- #endif
-
- if(pp == NULLPROC)
- return;
-
- /* Don't check the stack here!
- * Will cause infinite recursion if called from a stack error.
- */
-
- if(pp == Curproc)
- killself(); /* Doesn't return */
-
- /* Close any open sockets */
- freesock(pp);
- close_s(pp->input);
- close_s(pp->output);
-
- /* Stop alarm clock in case it's running */
- stop_timer(&pp->alarm);
-
- /* Alert everyone waiting for this proc to die */
- psignal(pp,0);
-
- /* Remove from appropriate table */
- delproc(pp);
-
- #ifdef PROCLOG
- if(!uploadstatus) {
- fprintf(proclog,"size %5u max %5u name %s\n",
- pp->stksize,stkutil(pp),pp->name);
- fflush(proclog);
- }
- #endif
-
- /* Free allocated memory resources */
- if(pp->freeargs){
- argv = pp->parg1;
- while(pp->iarg-- != 0)
- xfree(*argv++);
- xfree(pp->parg1);
- }
- xfree(pp->stack);
- xfree(pp);
- }
-
- /* Terminate current process by sending a request to the killer process.
- * Automatically called when a process function returns. Does not return.
- */
- void
- killself(void)
- {
- if(Curproc != NULLPROC) {
- struct mbuf *bp = pushdown(NULLBUF,sizeof(Curproc));
- memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
- enqueue(&Killq,bp);
- }
-
- /* "Wait for me; I will be merciful and quick." */
- for(;;) {
- pwait(NULL);
- }
- }
-
- /* Process used by processes that want to kill themselves */
- void
- killer(int i,void *v1,void *v2)
- {
- struct proc *pp;
- struct mbuf *bp;
-
- for(;;) {
- while(Killq == NULLBUF) {
- pwait(&Killq);
- }
- bp = dequeue(&Killq);
- pullup(&bp,(char *)&pp,sizeof(pp));
- free_p(bp);
- if(pp != Curproc) { /* We're immortal */
- killproc(pp);
- }
- }
- }
-
- /* Inhibit a process from running */
- void
- suspend(struct proc *pp)
- {
- if(pp == NULLPROC)
- return;
-
- if(pp != Curproc)
- delproc(pp); /* Running process isn't on any list */
-
- pp->state |= SUSPEND;
-
- if(pp != Curproc)
- addproc(pp); /* pwait will do it for us */
- else
- pwait(NULL);
- }
-
- /* Restart suspended process */
- void
- resume(struct proc *pp)
- {
- if(pp == NULLPROC)
- return;
-
- delproc(pp); /* Can't be Curproc! */
- pp->state &= ~SUSPEND;
- addproc(pp);
- }
-
- /* Wakeup waiting process, regardless of event it's waiting for. The process
- * will see a return value of "val" from its pwait() call.
- */
- void
- alert(struct proc *pp,void *val)
- {
- if(pp == NULLPROC)
- return;
-
- #ifdef XXX
- if((pp->state & WAITING) == 0)
- return;
- #endif
-
- #ifdef PROCTRACE
- tprintf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
- #endif
-
- if(pp != Curproc)
- delproc(pp);
-
- pp->state &= ~WAITING;
- pp->retval = val;
- pp->event = 0;
-
- if(pp != Curproc)
- addproc(pp);
- }
-
- /* Post a wait on a specified event and give up the CPU until it happens. The
- * null event is special: it means "I don't want to block on an event, but let
- * somebody else run for a while". It can also mean that the present process
- * is terminating; in this case the wait never returns.
- *
- * Pwait() returns 0 if the event was signaled; otherwise it returns the
- * arg in an alert() call. Pwait must not be called from interrupt level.
- *
- * Note that pwait can run with interrupts enabled even though it examines
- * a few global variables that can be modified by psignal at interrupt time.
- * These *seem* safe.
- */
- void *
- pwait(void *event)
- {
- struct proc *oldproc;
- void *tmp;
-
- if(Curproc != NULLPROC) { /* If process isn't terminating */
- if(Stkchk)
- chkstk();
-
- if(event == NULL) {
- /* Special case; just give up the processor.
- *
- * Optimization: if nothing else is ready, just return.
- */
- if(Rdytab == NULLPROC) {
- return 0;
- }
- } else {
- /* Post a wait for the specified event */
- Curproc->event = event;
- Curproc->state = WAITING;
- }
- addproc(Curproc);
- }
-
- /* Look for a ready process and run it. If there are none,
- * loop or halt until an interrupt makes something ready.
- */
- while(Rdytab == NULLPROC) {
- /* Give system back to upper-level multitasker, if any.
- * Note that this function enables interrupts internally
- * to prevent deadlock, but it restores our state
- * before returning.
- */
- giveup();
- }
-
- /* Remove first entry from ready list */
- oldproc = Curproc;
- Curproc = Rdytab;
- delproc(Curproc);
-
- /* Now do the context switch.
- * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
- *
- * If the old process has gone away, simply load the new process's
- * environment. Otherwise, save the current process's state. Then if
- * this is still the old process, load the new environment. Since the
- * new task will "think" it's returning from the setjmp() with a return
- * value of 1, the comparison with 0 will bypass the longjmp(), which
- * would otherwise cause an infinite loop.
- */
- #ifdef PROCTRACE
- if(strcmp(oldproc->name,Curproc->name) != 0){
- tprintf("-> %s(%d)\n",Curproc->name,!!Curproc->i_state);
- }
- #endif
- /* Note use of comma operator to save old interrupt state only if
- * oldproc is non-null
- */
- if(oldproc == NULLPROC
- || (oldproc->i_state = istate(), setjmp(oldproc->env) == 0)){
- /* We're still running in the old task; load new task context.
- * The interrupt state is restored here in case longjmp
- * doesn't do it (e.g., systems other than Turbo-C).
- */
- restore(Curproc->i_state);
- longjmp(Curproc->env,1);
- }
-
- /* At this point, we're running in the newly dispatched task */
- tmp = Curproc->retval;
- Curproc->retval = 0;
-
- /* Also restore the true interrupt state here, in case the longjmp
- * DOES restore the interrupt state saved at the time of the setjmp().
- * This is the case with Turbo-C's setjmp/longjmp.
- */
- restore(Curproc->i_state);
- return tmp;
- }
-
- /* Make ready the first 'n' processes waiting for a given event. The ready
- * processes will see a return value of 0 from pwait(). Note that they don't
- * actually get control until we explicitly give up the CPU ourselves through
- * a pwait(). Psignal may be called from interrupt level. It returns the
- * number of processes that were woken up.
- */
- int
- psignal(
- void *event, /* Event to signal */
- int n) /* Max number of processes to wake up */
- {
- struct proc *pp;
- int i_state;
- int cnt = 0; /* 0 means "signal everybody waiting" */
- // if(Stkchk)
- // DL8YQ chkstk();
-
- if(event == NULL)
- return 0; /* Null events are invalid */
-
- if(n == 0)
- n = 32766;
-
- i_state = dirps();
-
- for(pp = Waittab; pp != NULLPROC; pp = pp->next) {
- if(n == 0)
- break;
-
- if(pp->event == event){
- #ifdef PROCTRACE
- if(i_state){
- tprintf("psignal(%lx,%u) wake %lx [%s]\n",
- ptol(event),n,ptol(pp),pp->name);
- }
- #endif
- delproc(pp);
- pp->state &= ~WAITING;
- pp->event = 0;
- pp->retval = 0;
- addproc(pp);
- n--;
- cnt++;
- }
- }
-
- for(pp = Susptab; pp != NULLPROC; pp = pp->next) {
- if(n == 0)
- break;
-
- if(pp->event == event){
- #ifdef PROCTRACE
- if(i_state){
- tprintf("psignal(%lx,%u) wake %lx [%s]\n",
- ptol(event),n,ptol(pp),pp->name);
- }
- #endif
- delproc(pp);
- pp->state &= ~WAITING;
- pp->event = 0;
- pp->retval = 0;
- addproc(pp);
- n--;
- cnt++;
- }
- }
- restore(i_state);
- return cnt;
- }
-
- // #ifdef XXX
- /* Rename a process */
- void
- chname(struct proc *pp,char *newname)
- {
- sprintf(pp->name,"%.16s",newname);
- }
- // #endif